package org.tloss.web.editor.sql.editors;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.SQLException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.DialogCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.FilteredResourcesSelectionDialog;
import org.eclipse.ui.part.EditorPart;
import org.tloss.web.editor.Utils;
import org.tloss.web.editor.database.editors.DatabaseConnect;
import org.tloss.web.editor.model.Database;
import org.tloss.web.editor.model.Sql;
import org.tloss.web.editor.utils.Constants;

public class SQLMainEditor extends EditorPart implements
		IResourceChangeListener {
	private Sql sql;

	private boolean dirty = false;
	TreeViewer treeViewer;

	public Sql getSql() {
		return sql;
	}

	public void doSave(IProgressMonitor monitor) {
		IEditorInput editorInput = this.getEditorInput();
		IFileEditorInput fileEditorInput = (IFileEditorInput) editorInput;
		IFile file = fileEditorInput.getFile();
		JAXBContext context;
		try {
			context = JAXBContext.newInstance(Sql.class);
			Marshaller marshaller = context.createMarshaller();
			ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
			marshaller.marshal(sql, arrayOutputStream);

			file.setContents(
					new ByteArrayInputStream(arrayOutputStream.toByteArray()),
					false, true, monitor);
			this.dirty = false;
			this.firePropertyChange(IEditorPart.PROP_DIRTY);
		} catch (JAXBException e) {
			Utils.logError("Can't save sql file", e);
		} catch (CoreException e) {
			Utils.logError("Can't save sql file", e);
		}

	}

	public void doSaveAs() {

	}

	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		if (!(input instanceof IFileEditorInput)) {
			PartInitException exception =  new PartInitException("Input must be a file");
			Utils.logError("Input must be a file", exception);
			throw  exception;
		}
		setSite(site);
		setInput(input);
		IFileEditorInput editorInput = (IFileEditorInput) input;
		IFile file = editorInput.getFile();
		JAXBContext context;
		InputStream inputStream = null;
		try {
			inputStream = file.getContents();
			if (inputStream.available() == 0) {
				sql = new Sql();
			} else {
				context = JAXBContext.newInstance(Sql.class);
				Unmarshaller marshaller = context.createUnmarshaller();
				sql = (Sql) marshaller.unmarshal(inputStream);
				if (sql.getDatabaseResource() != null) {
					IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin
							.getWorkspace().getRoot();
					IFile iFile = myWorkspaceRoot.getFile(new Path(sql
							.getDatabaseResource()));
					if (iFile != null) {
						context = JAXBContext.newInstance(Database.class);
						marshaller = context.createUnmarshaller();
						inputStream = iFile.getContents();
						if (inputStream.available() > 0) {
							sql.setDatabase((Database) marshaller
									.unmarshal(inputStream));
						}
					}
				}
			}

		} catch (CoreException e) {
			PartInitException exception =  new PartInitException("Can't load resource",e);
			Utils.logError("Can't load resource", exception);
			throw  exception;
		} catch (JAXBException e) {
			PartInitException exception =  new PartInitException("Can't load resource",e);
			Utils.logError("Can't load resource", exception);
			throw  exception;
		} catch (IOException e) {
			PartInitException exception =  new PartInitException("Can't load resource",e);
			Utils.logError("Can't load resource", exception);
			throw  exception;
		} finally {
			try {
				if (inputStream != null) {
					inputStream.close();
				}
			} catch (IOException e) {
				Utils.logError("Can't close inputstream resource", e);
			}
		}
	}

	public boolean isDirty() {

		return dirty;
	}

	public boolean isSaveAsAllowed() {

		return false;
	}

	public void createPartControl(Composite parent) {
		Composite composite = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		composite.setLayout(layout);
		layout.numColumns = 2;

		Composite treeContainer = new Composite(composite, SWT.BORDER);
		GridData gridData = new GridData();
		treeContainer.setLayoutData(gridData);
		gridData.horizontalAlignment = SWT.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.verticalAlignment = SWT.FILL;
		gridData.grabExcessVerticalSpace = true;
		TreeColumnLayout treeLayout = new TreeColumnLayout();
		treeContainer.setLayout(treeLayout);
		treeViewer = new TreeViewer(treeContainer, SWT.MULTI
				| SWT.FULL_SELECTION);
		Tree tree = treeViewer.getTree();
		tree.setHeaderVisible(true);
		TreeColumn keyColumn;
		TreeColumn valueColumn;

		keyColumn = new TreeColumn(tree, SWT.NONE);
		keyColumn.setText("Name");
		treeLayout.setColumnData(keyColumn, new ColumnWeightData(2));

		valueColumn = new TreeColumn(tree, SWT.NONE);
		valueColumn.setText("Value");
		treeLayout.setColumnData(valueColumn, new ColumnWeightData(2));

		treeViewer.setContentProvider(new ITreeContentProvider() {
			public void dispose() {

			}

			public void inputChanged(Viewer arg0, Object arg1, Object arg2) {

			}

			@Override
			public Object[] getChildren(Object arg0) {
				return getElements(arg0);
			}

			@Override
			public Object[] getElements(Object arg0) {
				if (arg0 instanceof Sql)
					return new Object[] { "Database", "Mode" };
				return new Object[] {};
			}

			@Override
			public Object getParent(Object arg0) {
				return null;
			}

			@Override
			public boolean hasChildren(Object arg0) {
				if (arg0 instanceof Sql)
					return true;
				return false;
			}
		});
		// final DatabaseConfigLableProvider treeLabelProvider = new
		// DatabaseConfigLableProvider();
		// treeViewer.setLabelProvider(treeLabelProvider);

		TreeViewerColumn column1 = new TreeViewerColumn(treeViewer, keyColumn);

		column1.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if ("Database".equals(element))
					return "Database";
				else if ("Mode".equals(element))
					return "Mode";
				return "";
			}

			public Image getImage(Object element) {

				return null;
			}
		});

		TreeViewerColumn column2 = new TreeViewerColumn(treeViewer, valueColumn);
		column2.setLabelProvider(new ColumnLabelProvider() {
			public String getText(Object element) {
				if ("Database".equals(element))
					return sql.getDatabaseResource() != null ? sql
							.getDatabaseResource() : "";
				else if ("Mode".equals(element))
					return sql.getMode() != null ? sql.getMode() : "";
				return "";
			}

			public Image getImage(Object element) {

				return null;
			}
		});

		column2.setEditingSupport(new EditingSupport(treeViewer) {
			ComboBoxCellEditor boxCellEditor = new ComboBoxCellEditor(
					(Composite) treeViewer.getControl(), new String[] {
							Constants.SQL_SELECT_MODE,
							Constants.SQL_INSERT_MODE,
							Constants.SQL_UPDATE_MODE,
							Constants.SQL_DELETE_MODE });

			DialogCellEditor libEditor = new DialogCellEditor(
					(Composite) treeViewer.getControl()) {

				@Override
				protected Object openDialogBox(Control cellEditorWindow) {
					IProject scope = ((IFileEditorInput) getEditorInput())
							.getFile().getProject();
					IResource container = scope
							.findMember(Constants.DATABASE_FOLDER);
					if (container != null
							&& container.getType() == IResource.FOLDER) {
						FilteredResourcesSelectionDialog dialog = new FilteredResourcesSelectionDialog(
								treeViewer.getTree().getShell(), false,
								(IFolder) container, IResource.FILE);

						dialog.open();
						Object object = dialog.getFirstResult();
						if (object != null) {
							IFile file = (IFile) object;
							return file.getFullPath().toString();
						}
					}
					return "";
				}
			};

			protected boolean canEdit(Object element) {
				return true;
			}

			protected CellEditor getCellEditor(Object element) {
				if ("Database".equals(element))
					return libEditor;
				else if ("Mode".equals(element))
					return boxCellEditor;
				return null;
			}

			protected Object getValue(Object element) {
				if ("Database".equals(element))
					return sql.getDatabaseResource() != null ? sql
							.getDatabaseResource() : "";
				else if ("Mode".equals(element)) {
					if (Constants.SQL_INSERT_MODE.equals(sql.getMode())) {
						return 1;
					} else if (Constants.SQL_UPDATE_MODE.equals(sql.getMode())) {
						return 2;
					} else if (Constants.SQL_DELETE_MODE.equals(sql.getMode())) {
						return 3;
					} else {
						return 0;
					}
				}
				return null;
			}

			protected void setValue(Object element, Object value) {
				if ("Database".equals(element))
					sql.setDatabaseResource(value.toString());
				else if ("Mode".equals(element)) {
					if (Integer.valueOf(1).equals(value)) {
						sql.setMode(Constants.SQL_INSERT_MODE);
					} else if (Integer.valueOf(2).equals(value)) {
						sql.setMode(Constants.SQL_UPDATE_MODE);
					} else if (Integer.valueOf(3).equals(value)) {
						sql.setMode(Constants.SQL_DELETE_MODE);
					} else {
						sql.setMode(Constants.SQL_SELECT_MODE);
					}
				}
				treeModified(element);
			}

			private void treeModified(Object element) {
				treeViewer.refresh(element);
				dirty = true;
				firePropertyChange(IEditorPart.PROP_DIRTY);
			}
		});

		getSite().setSelectionProvider(treeViewer);

		treeViewer.setInput(sql);

		treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);

		Composite wrapper = new Composite(composite, SWT.NONE);
		RowLayout rowLayout = new RowLayout();
		wrapper.setLayout(rowLayout);
		rowLayout.type = SWT.VERTICAL;

		final Button button = new Button(wrapper, SWT.NONE);
		button.setText("Test connection");

		button.addMouseListener(new MouseListener() {

			public void mouseUp(MouseEvent e) {

			}

			public void mouseDown(MouseEvent e) {
				URL jarUrl;
				StringBuffer buffer = new StringBuffer();
				boolean connected = false;
				Database database = sql.getDatabase();
				if (database == null) {
					return;
				}
				try {
					jarUrl = new URL("jar", "", "file:"
							+ new File(database.getJdbcLib()).getAbsolutePath()
							+ "!/");
					URLClassLoader classLoader = new URLClassLoader(
							new URL[] { jarUrl }, this.getClass()
									.getClassLoader());

					DatabaseConnect connect = new DatabaseConnect(database
							.getJdbcURL(), database.getJdbcUsername(), database
							.getJdbcPassword(), database.getDriverClass(),
							classLoader);
					Connection connection = connect.getConnection();
					if (connection != null) {
						connected = true;
						MessageBox messageBox = new MessageBox(button
								.getShell(), SWT.OK);
						messageBox.setMessage("Connection is success");
						messageBox.open();
					}
				} catch (MalformedURLException e1) {
					Utils.logError("Can't connect to DB", e1);
					buffer.append(e1.getMessage());
				} catch (SQLException e1) {
					Utils.logError("Can't connect to DB", e1);
					buffer.append(e1.getMessage());
				} catch (ClassNotFoundException e1) {
					Utils.logError("Can't connect to DB", e1);
					buffer.append(e1.getMessage());
				} catch (InstantiationException e1) {
					Utils.logError("Can't connect to DB", e1);
					buffer.append(e1.getMessage());
				} catch (IllegalAccessException e1) {
					Utils.logError("Can't connect to DB", e1);
					buffer.append(e1.getMessage());
				}
				if (!connected) {
					MessageBox messageBox = new MessageBox(button.getShell(),
							SWT.OK);
					messageBox.setMessage("Connection is fail. "
							+ buffer.toString());
					messageBox.open();
				}
			}

			public void mouseDoubleClick(MouseEvent e) {

			}
		});
	}

	public void setFocus() {

	}

	@Override
	public void resourceChanged(IResourceChangeEvent arg0) {
		dirty = true;
		firePropertyChange(IEditorPart.PROP_DIRTY);
	}

}
